/**
 * njsvm  module
 * 兼容 NodeJs的 require 函数
 *
 * $Id$
 * @author 老雷 <leizongmin@gmail.com>
 * @version 0.22
 * @date 2011-07-12 10:41:25
 */
 
var vm		= require('vm'),
	path	= require('path'),
	fs		= require('fs'),
	mysql	= require('./mysql');
 
njsmodule = {};

CACHE = {};

njsmodule.debug = function (x) {
	console.log('[njsmodule] ' + x.toString());
}

njsmodule.wrap = function (c) {
	return '(function () { \n ' +
			//'var require = ' +
			c + '\n });';
}

// 加载程序 n=名称, d=所在目录, sandbox=沙箱
njsmodule.require = function () {
	if (arguments.length < 1) {
		return 'Not enough arguments!';
	}
	if (arguments.length == 1) {
		var n = arguments[0], d = __dirname, sandbox = {};
	}
	else if (arguments.length == 2) {
		var n = arguments[0], d = __dirname, sandbox = arguments[1];
	}
	else {
		var n = arguments[0], d = arguments[1], sandbox = arguments[2];
	}
	
	//njsmodule.debug('require dir: ' + d);
	
	try {
		// 如果是mysql模块
		if (n == 'mysql') {
			return mysql;
		}
	
		// 如果是系统模块
		if (n.charAt(0) != '.') {
			return require(n);
		}
		
		// 取得实际文件名
		if (n.charAt(0) != '/') {
			n = path.resolve(d, n);
		}
		var filename = njsmodule.findModule(n);
		
		// 没有找到模块文件
		if (!filename) {
			njsmodule.debug('Cannot find the module "' + n + '".');
			return 'Cannot find the module "' + n + '".';
		}
		
		// 检查是否在缓存中
		if (!(filename in CACHE)) {
			// 首次编译
			njsmodule.debug('compile ' + filename);
			
			var c = fs.readFileSync(filename);
			var s = vm.createScript(njsmodule.wrap(c), filename);
			
			for (var k in global) {
				sandbox[k] = global[k];
			}
			var requireModule = { exports: {}, parent: module};
			sandbox.exports = requireModule.exports;
			sandbox.__filename = filename;
			sandbox.__dirname = path.dirname(filename);
			sandbox.module = requireModule;
			sandbox.global = sandbox;
			sandbox.root = sandbox;
			sandbox.require = function (n) { return njsmodule.require(n, sandbox.__dirname, {}); };
			
			var f = s.runInNewContext(sandbox);
			f.apply();
			
			// njsmodule.debug('----------------------------');
			// njsmodule.debug(sandbox.exports.toString());
			/*
			console.log('\n' + filename);
			for (i in sandbox.exports) { console.log(i + '=' + sandbox.exports[i]); }
			console.log('\n');
			*/
			
			CACHE[filename] = {
				filename: filename,
				script: s,
				exports: requireModule.exports
				}
				
			// 监视文件是否改动
			fs.unwatchFile(filename);
			fs.watchFile(filename, function (curr, prev) {
				njsmodule.debug('removeCache ' + filename);
				delete CACHE[filename];
			});
		}
		
		/*
		if (/test2/.test(filename)) {
			console.log('\n test2');
			console.log(CACHE[filename].exports);
			console.log('\n\n');
		}
		*/
		
		return CACHE[filename].exports;
	}
	
	catch (err) {
		njsmodule.debug('compile error: \n' + err.stack);
		//return err.stack;
		throw err;
	}
}

// 查找模块路径 n = 文件名, 必须以/开头
njsmodule.findModule = function(n) {
	var paths = [];
	var pdir = n;
	var basename = path.basename(n);
	var notParentDir = true;
	do {
		pdir = path.dirname(pdir);
		if (notParentDir) {
			paths.push(pdir);
			notParentDir = false;
		}
		if (pdir == '/') {
			paths.push(pdir + 'node_modules');
			break;
		}
		else {
			paths.push(pdir + '/node_modules');
		}
	} while (true);
	
	for (i in paths) {
		if (path.extname(basename) == '') {
			var files = [basename + '.node', basename + '.js', basename + '/index.js' ];
		}
		else {
			var files = [basename];
		}
		for (j in files) {
			var filename = path.resolve(paths[i], files[j]);
			try {
				//console.log('test ' + filename);
				var stat = fs.statSync(filename);
				if (stat.isFile()) {
					return filename;
				}
			}
			catch (err) {}
		}
	}
}


/** 模块输出 */
exports.require = njsmodule.require;


// 
/*
var sandbox = {};
var x = njsmodule.require('./test1', sandbox);
for (i in sandbox) {
	//njsmodule.debug('sandbox.' + i + '=' + sandbox[i]);
}
*/
/*
x = njsmodule.require('net');
for (i in x) {
	njsmodule.debug('x.' + i + '=' + x[i]);
}
*/
//x.hello();
//console.log(CACHE);

/*
var m = njsmodule.require('mysql');
//var query = njsmodule.require('
x = new m.Client();
//console.log(q = new 
//console.log(mysql);
//console.log(mysql.toString());
for (i in CACHE) {
	//console.log(CACHE[i]);
}
x.host = '127.0.0.1';
x.user = 'root';
x.database = 'hi624';
x.connect(function (err) {
	console.log('mysql: ' + err);
	//console.log(x);
	x.query('SELECT * FROM ac_user LIMIT 2', [], function () {
		console.log(arguments[1]);
		x.end();
	});
});
*/
